﻿﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BattleResolver : MonoBehaviour
{
    public static GameObject OverWatchZone;

    private void Awake()
    {
        OverWatchZone = Resources.Load<GameObject>("Prefabs/OverWatchZone");
    }

    // 调用入口
    public static bool ExecuteCardAction(IEnumerable cardActions, GameObject caller, GameObject receiver, Vector3 targetPosition, GameObject fxPrefab = null)
    {
        foreach (Action action in cardActions)
        {
            // 判断目标类型
            List<GameObject> targets = new List<GameObject>();

            switch (action.targetType)
            {
                case TargetType.Self:
                    targets.Add(caller);
                    break;
                case TargetType.Target:
                    targets.Add(receiver);
                    break;
                case TargetType.Range:
                    targets.Add(caller);
                    targets.Add(receiver);
                    break;
                case TargetType.SelfAndTarget:
                    break;
                default:
                    return false;
            }
            
            // 再判断效果类型
            // 送到对应的执行器
            if (targets.Count == 0)
            {
                // 送到范围的
                ExecuteRangeAction(action, caller, targetPosition);
            }
            else
            {
                caller.GetComponent<BaseEntity>().attackListener = () =>
                {
                    if (fxPrefab)
                    {
                        Vector3 callerPosition = caller.transform.position;
                        callerPosition.z = -1;
                        
                        GameObject fxObject = GameObject.Instantiate(fxPrefab, callerPosition, Quaternion.identity);
//        fxObject.transform.SetParent(GameObject.FindGameObjectWithTag(StaticDataManager.PLAYER_TAG).transform);

                        fxObject.GetComponent<Projectile>().SetTargetPoint(receiver.transform.position);            
                    }
                    
                    // 送到单体的
                    foreach (var target in targets)
                    {
                        ExecuteTargetAction(action, caller, target);
                    }
                };
            }
            
            
            // 然后看看还有没有下一个执行对象
            if (action.nextActions.Count > 0)
            {
                // TODO 看看接下来的效果是不是需要触发的Buff
                // TODO 根据buff的对象类型施加到 receiver 或者 caller 上面
                for (int i = 0; i < action.nextActions.Count; i++)
                {
                    var subAction = action.nextActions[i];
                    
                    if (subAction.isBuff)
                    {
                        subAction.caller = caller;
                        subAction.receiver = receiver;

                        if (subAction.effectTriggerType == EntityStatusEnum.OverWatching)
                        {
                            receiver.GetComponent<BaseEntity>().SetOverWatch(subAction);
                            GameObject overWatchZone = Instantiate(OverWatchZone, receiver.transform, false);

                            ObjectInRange objectInRange = overWatchZone.GetComponent<ObjectInRange>(); 
                            objectInRange.shapeType = ShapeType.Star;
                            objectInRange.transform.position = receiver.transform.position;
                            
                            objectInRange.InitialCollider();
                            objectInRange.FlushColliderZone(subAction.values[0]);

                            //  然后创建一个检查zone
                            //  添加到receiver的子类
                            //  然后设置检查区的参数
                            //  启动检查区
                            //  然后将接受者的处理函数添加到检查区里面
                            objectInRange.objectIncomeEvent += receiver.GetComponent<BaseEntity>().DealWithOverWatch;
                            
                            continue;
                        }
                        
                        if (subAction.targetType == TargetType.Self || subAction.targetType == TargetType.SelfAndTarget)
                        {
                            caller.GetComponent<BaseEntity>().AddBuff(subAction);
                        }
                        
                        if (subAction.targetType == TargetType.Target || subAction.targetType == TargetType.SelfAndTarget)
                        {
                            receiver.GetComponent<BaseEntity>().AddBuff(subAction);
                        }
                    }
                    else
                    {
                        ExecuteCardAction(action.nextActions, caller, receiver, targetPosition, fxPrefab);                        
                    }
                }
            }
        }
        
        caller.GetComponent<BaseEntity>()._status = EntityStatusEnum.Attack;
        
        return true;
    }
    
    public static bool DealWithCardEffect(GameObject caller, GameObject receiver,CardScriptable cardData, Vector3 targetPosition)
    {
        // TODO 这个转交给BR来进行操作
        switch (cardData.targetType)
        {
            // 如果卡的类型是范围，然后指定的坐标是空坐标，那么不执行
            case TargetType.Range:
                if (targetPosition == Vector3.zero)
                {
                    return false;
                }
                
                break;
            // 如果卡的类型是目标，然后没有指定的目标，那么不执行
            case TargetType.Target:
                if (!receiver)
                {
                    return false;
                }

                targetPosition = receiver.transform.position;
                
                break;
            // 如果卡的目标是自己，然后没有指定的目标，那么不执行
            case TargetType.Self:
                if (!receiver)
                {
                    return false;
                }

                targetPosition = receiver.transform.position;
                break;
        }
        // TODO 让执行者进入攻击状态
        caller.GetComponent<BaseEntity>().is_need_play_next_animation = true;
        caller.GetComponent<BaseEntity>().next_animation_type = cardData.attackType;
        
        receiver.GetComponent<BaseEntity>().beater = caller;


        // TODO 然后处理动画效果，处理完之后才开始执行伤害计算

        ExecuteCardAction(cardData.nextActions,
            caller: caller,
            receiver: receiver,
            targetPosition: targetPosition,
            cardData.fxPrefab);

        return true;
    }
    
    public static bool IsReceiverInCardRange(GameObject caller, GameObject receiver, GameObject cardInstance, String layerName)
    {
        CardScriptable cardData = cardInstance.GetComponent<BasicCard>().pairData.cardData;

        Collider2D[] hits = TileManager.GetRangeCollider2Ds(caller.transform.position, cardData.range, cardData.rangeType, layerName);
        
        foreach (Collider2D hit in hits)
        {
            if (hit.gameObject == receiver)
            {
                return true;
            }
        }
        
        return false;
    }

    public static bool IsCardCanUseInBaseInfo(GameObject caller, GameObject cardInstance)
    {
        // TODO 施放的基本条件是否满足
        // TODO 耗血 耗魔 耗行动

        BaseEntity callerEntity = caller.GetComponent<BaseEntity>();
        try
        {
            CardScriptable cardData = cardInstance.GetComponent<BasicCard>().pairData.cardData;
            
            if (callerEntity._mp >= cardData.cost)
            {
                return true;
            }
        }
        catch (Exception e)
        {
            Debug.Log(e);
            return false;
        }

        return false;
    }
    
    // 通过 TargetType 来进行初筛
    private static void ExecuteTargetAction(Action action, GameObject caller, GameObject target)
    {
        switch (action.effectType)
        {
            case EffectType.Hurt:
                // TODO 调用 伤害函数(施加对象, 伤害数值);
                Hurt(target, action.values[0]);
                break;
            case EffectType.Heal:
                // TODO 调用 回血函数(施加对象, 回血数值);
                Heal(target, action.values[0]);
                break;
            case EffectType.GroundEffect:
                // TODO 调用 地形函数(施加坐标, 地形效果SO, 扩展格数, 持续时间);
                GroundEffect(target.transform.position, null, action.values[2], action.values[1]);
                break;
            case EffectType.Buff:
                // TODO 调用 BUFF函数(施加对象, BUFFSO, 持续时间);
                Buff(target, null, action.values[0]);
                break;
            case EffectType.DropCard:
                // TODO 调用 扔卡函数(施加对象, 扔卡张数); 
                DrawCard(target, 1);
                break;
            case EffectType.Guard:
                // TODO 调用 加盾函数(施加对象, 回血数值);
                Guard(target, action.values[0]);
                break;
            default:
                break;
        }
    }


    private static void ExecuteRangeAction(Action action, GameObject caller, Vector3 targetPosition)
    {
        switch (action.effectType)
        {
            case EffectType.Hurt:
                // TODO 调用 伤害函数(施加坐标, 扩展格数，伤害数值);
                Hurt(targetPosition, action.values[0], action.values[1]);
                break;
            case EffectType.Heal:
                // TODO 调用 回血函数(施加坐标, 扩展格数, 回血数值);
                Heal(targetPosition, action.values[0], action.values[1]);
                break;
            case EffectType.GroundEffect:
                // TODO 调用 地形函数(施加坐标, 地形效果SO, 扩展格数, 持续时间);
                GroundEffect(targetPosition, null, action.values[0], action.values[1]);
                break;
            case EffectType.Buff:
                // TODO 调用 BUFF函数(施加坐标, BUFFSO, 扩展格数, 持续时间);
                Buff(targetPosition, null, action.values[0], action.values[1]);
                break;
            case EffectType.DropCard:
                // TODO 调用 扔卡函数(施加坐标, 扩展格数, 扔卡张数); 
                DrawCard(targetPosition, action.values[0], action.values[1]);
                break;
            case EffectType.Guard:
                // TODO 调用 扔卡函数(施加坐标, 扩展格数, 扔卡张数); 
                Guard(targetPosition, action.values[0], action.values[1]);
                break;
            default:
                break;
        }
    }

    #region 具体执行单元

    private static List<GameObject> GetRangeGameObjects(Vector3 targetPosition)
    {
        return new List<GameObject>();
    }

    // ------------------------------------------------------------------- //


    private static void Hurt(GameObject target, int hurtValue)
    {
        Debug.Log($"降低目标 [{target.tag}] 生命值 [{hurtValue}] 点");
        
        // TODO 应该使用扣血函数的
        BaseEntity entity = target.GetComponent<BaseEntity>();
        if (entity)
        {
            entity.DealDamage(hurtValue);
            
            entity._status = EntityStatusEnum.Beaten;
            entity.is_need_play_next_animation = true;
        }
    }

    private static void Hurt(Vector3 targetPosition, int detectRange, int hurtValue)
    { 
        // TODO 根据范围获取对应的target
        foreach (GameObject target in GetRangeGameObjects(targetPosition))
        {
            // TODO target 是否合乎规则
            // 然后调用普通的Hurt
            
            Hurt(target, hurtValue);
        }
    }

    // ------------------------------------------------------------------- //

    private static void Heal(GameObject target, int healValue)
    {
        Debug.Log($"回复目标 [{target.tag}] 生命值 [{healValue}] 点");
        
        // TODO 应该使用回血函数的
            
        BaseEntity entity = target.GetComponent<BaseEntity>();
        if (entity)
        {
            if (entity._hp + healValue >= entity._hp_max)
            {
                entity._hp = entity._hp_max;
            }
            else
            {
                entity._hp += healValue;                
            }
             
            entity.FlushStatus();
        }
    }

    private static void Heal(Vector3 targetPosition, int detectRange, int healValue)
    {
        // TODO 根据范围获取对应的target
        foreach (GameObject target in GetRangeGameObjects(targetPosition))
        {
            // TODO target 是否合乎规则
            // 然后调用普通的Heal
            Heal(target, healValue);
        }
    }

    // ------------------------------------------------------------------- //

    private static void Guard(GameObject target, int shieldValue)
    {
        Debug.Log($"增加目标 [{target.tag}] 护盾 [{shieldValue}] 点");
        
        // TODO 应该使用加盾函数的
            
        BaseEntity entity = target.GetComponent<BaseEntity>();
        if (entity)
        {
            entity._shield += shieldValue;
            entity.FlushStatus();
        }
    }

    private static void Guard(Vector3 targetPosition, int detectRange, int shieldValue)
    {
        // TODO 根据范围获取对应的target
        foreach (GameObject target in GetRangeGameObjects(targetPosition))
        {
            // TODO target 是否合乎规则
            // 然后调用普通的Heal
            Guard(target, shieldValue);
        }
    }
    
    // ------------------------------------------------------------------- //

    private static void DrawCard(GameObject target, int drawValue)
    {
        throw new NotImplementedException();
    }
    private static void DrawCard(Vector3 targetPosition, int detectRange, int drawValue)
    {
        throw new NotImplementedException();
    }

    // ------------------------------------------------------------------- //

    private static void Buff(GameObject target, object buffSO, int buffValue)
    {
//        target.GetComponent<BaseEntity>().AddBuff(buffSO);
        return;
    }

    private static void Buff(Vector3 targetPosition, object buffSO, int detectRange, int buffValue)
    {
        foreach (GameObject target in GetRangeGameObjects(targetPosition))
        {
            // TODO target 是否合乎规则
            // 然后调用普通的Heal
            Buff(target, buffSO, buffValue);
        }
    }

    // ------------------------------------------------------------------- //

    private static void GroundEffect(Vector3 position, object groundEffectSO, int detectRange, int effectValue)
    {
        throw new NotImplementedException();
    }

    // ------------------------------------------------------------------- //
    

    #endregion

}
